﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

namespace ZilLion.Service.Core.WebSocket
{
    public class WebSocketConnectionManager
    {
        private readonly ConcurrentDictionary<string, List<string>> _groups =
            new ConcurrentDictionary<string, List<string>>();

        private readonly ConcurrentDictionary<string, System.Net.WebSockets.WebSocket> _sockets =
            new ConcurrentDictionary<string, System.Net.WebSockets.WebSocket>();

        public System.Net.WebSockets.WebSocket GetSocketById(string id)
        {
            return _sockets.FirstOrDefault(p => p.Key == id).Value;
        }

        public IList<System.Net.WebSockets.WebSocket> GetSocketsById(string id)
        {
            return _sockets.Where(p => p.Key == id).Select(x => x.Value).ToList();
        }

        public ConcurrentDictionary<string, System.Net.WebSockets.WebSocket> GetAll()
        {
            return _sockets;
        }

        public List<string> GetAllFromGroup(string groupId)
        {
            if (_groups.ContainsKey(groupId))
                return _groups[groupId];

            return default(List<string>);
        }
        public string GetGroupByWebSocketId(string webSocketId)
        {
            return _groups.FirstOrDefault(x => x.Value.Any(y => y == webSocketId)).Key;
            
        }
        public string GetId(System.Net.WebSockets.WebSocket socket)
        {
            return _sockets.FirstOrDefault(p => p.Value == socket).Key;
        }

        public void AddSocket(System.Net.WebSockets.WebSocket socket)
        {
            _sockets.TryAdd(CreateConnectionId(), socket);
        }

        public void AddSocket(string socketId, System.Net.WebSockets.WebSocket socket)
        {
            _sockets.TryAdd(socketId, socket);
        }

        public void AddToGroup(string socketId, string groupId)
        {
            if (_groups.ContainsKey(groupId))
            {
                var list = _groups[groupId];
                list.Add(socketId);
                _groups[groupId] = list;

                return;
            }

            _groups.TryAdd(groupId, new List<string> {socketId});
        }

        public void RemoveFromGroup(string socketId, string groupId)
        {
            if (_groups.ContainsKey(groupId))
            {
                var list = _groups[groupId];
                list.Remove(socketId);
                _groups[groupId] = list;
            }
        }

        public async Task RemoveSocket(string id)
        {
            System.Net.WebSockets.WebSocket socket;
            _sockets.TryRemove(id, out socket);

            await socket.CloseAsync(WebSocketCloseStatus.NormalClosure,
                "Closed by the WebSocketManager",
                CancellationToken.None).ConfigureAwait(false);
        }

        private string CreateConnectionId()
        {
            return Guid.NewGuid().ToString();
        }
    }
}